package com.gitee.elf.core.entity

import com.gitee.elf.api.annotation.Id
import com.gitee.elf.api.event.ElfEntityCreateEvent
import com.gitee.elf.api.nms.NMSEntity
import com.gitee.elf.util.files
import org.bukkit.entity.Entity
import taboolib.common.LifeCycle
import taboolib.common.io.runningClasses
import taboolib.common.platform.Awake
import taboolib.common.platform.function.info
import taboolib.common.util.random
import taboolib.common5.clong
import taboolib.platform.util.getMeta
import taboolib.platform.util.getMetaFirst
import taboolib.platform.util.getMetaFirstOrNull

object EntityManager {

    val entityMappings = mutableMapOf<String, Class<ProxyEntity<*>>>()

    val entityThemes = mutableMapOf<String, EntityTheme>()

    @Suppress("UNCHECKED_CAST")
    @Awake(LifeCycle.LOAD)
    fun loadEntityMappings() {
        runningClasses.forEach {

            if (ProxyEntity::class.java.isAssignableFrom(it) && it.isAnnotationPresent(Id::class.java)) {
                val annotation = it.getAnnotation(Id::class.java)
                entityMappings[annotation.value] = it as Class<ProxyEntity<*>>
            }
        }
    }

    @Awake(LifeCycle.ENABLE)
    fun loadEntityThemes() {
        entityThemes.clear()
        files("entity", listOf("wolf.yml")) {
            entityThemes[it.nameWithoutExtension] = EntityTheme(it)
        }
    }

    fun getEntityTheme(id: String): EntityTheme? {
        return entityThemes[id]
    }

    fun getEntityMappingClass(name: String): Class<ProxyEntity<*>>? {
        return entityMappings[name]
    }

    fun createEntityInstance(owner: Entity, theme: String): EntityInstance? {
        return createEntityInstance(owner, getEntityTheme(theme) ?: return null)
    }

    fun createEntityInstance(owner: Entity, theme: EntityTheme): EntityInstance? {

        if (ElfEntityCreateEvent.Pre(owner, theme).call()) {
            val entityInstance = EntityInstance(random(1, 99999999).clong, owner, theme.id)
            entityInstance.status = EntityStatus.STANDBY
            ElfEntityCreateEvent.Post(owner, entityInstance).call()
            return entityInstance
        }

        return null
    }

    val EntityInstance.bukkitMappingInstance: AbstractBukkitProxyEntity<*>?
        get() = mappingInstance as? AbstractBukkitProxyEntity<*>

    fun Entity.getEntityInstance(): EntityInstance? {
        return this.getMetaFirstOrNull("@EntityInstance")?.value() as? EntityInstance
    }

}